package com.study.cloud.gateway.core;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableMap;
import com.study.cloud.config.api.ConfigCenter;
import com.study.cloud.gateway.common.constants.BasicConst;
import com.study.cloud.gateway.common.rule.DynamicConfigManager;
import com.study.cloud.gateway.common.rule.ServiceDefinition;
import com.study.cloud.gateway.common.rule.ServiceInstance;
import com.study.cloud.gateway.common.util.NetUtils;
import com.study.cloud.gateway.core.config.Config;
import com.study.cloud.gateway.core.config.ConfigLoader;
import com.study.cloud.gateway.core.container.Container;
import com.study.cloud.registry.api.RegisterCenterListener;
import com.study.cloud.registry.api.RegistryCenter;
import lombok.extern.slf4j.Slf4j;

import java.util.ServiceLoader;
import java.util.Set;

/**
 * @author wangwancheng
 * @create 2025/7/17 13:53
 */
@Slf4j
public class GatewayBootstrap {
    public static void main(String[] args) {
        //加载网关的核心配置
        Config config = ConfigLoader.getInstance().load(args);
        System.out.println(config.getPort());
        //组件的初始化 netty
        //配置中信服务器初始化，链接配置中信，监听配置中信的新增 修改 删除
        initAndGetConfig(config);
        //启动容器
        Container container = new Container(config);
        container.start();
        //链接注册中心。将注册中信的实例加载到本地
        final RegistryCenter registryCenter = registerAndSubscribe(config);
        //服务优雅关闭
        //接受 kill 信号
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                registryCenter.deRegister(buildGatewayServiceDefinition(config),buildGatewayServiceInstance(config));
            }
        }));
    }

    private static RegistryCenter registerAndSubscribe(Config config) {
        ServiceLoader<RegistryCenter> serviceLoader = ServiceLoader.load(RegistryCenter.class);
        RegistryCenter registryCenter = serviceLoader.iterator().next();
        if (registryCenter == null){
            log.error("not found ConfigCenter impl");
            throw new RuntimeException("not found ConfigCenter impl");
        }
        //初始化
        registryCenter.init(config.getRegistryAddress(), config.getEnv());
        //构建网关的服务定义和服务实例
        ServiceDefinition serviceDefinition = buildGatewayServiceDefinition(config);
        ServiceInstance serviceInstance = buildGatewayServiceInstance(config);
        //注册
        registryCenter.register(serviceDefinition, serviceInstance);
        //订阅监听
        registryCenter.subscribeAllServices(new RegisterCenterListener() {
            @Override
            public void onChange(ServiceDefinition serviceDefinition, Set<ServiceInstance> serviceInstance) {
                log.info("onChange serviceDefinition:{},serviceInstance:{}", JSON.toJSONString(serviceDefinition), JSON.toJSONString(serviceInstance));
                 DynamicConfigManager.getInstance().addServiceInstance(serviceDefinition.getUniqueId(), serviceInstance);
                DynamicConfigManager.getInstance().addServiceDefinition(serviceDefinition.getUniqueId(), serviceDefinition);
            }
        });
        return registryCenter;
    }

    /**
     * 构建服务的定义信息
     * @param config
     * @return
     */
    private static ServiceDefinition buildGatewayServiceDefinition(Config config) {
        return ServiceDefinition.builder()
                .serviceId(config.getApplicationName())
                .uniqueId(config.getApplicationName())
                .envType(config.getEnv())
                .invokeMap(ImmutableMap.of())
                .build();
    }

    /**
     * 构建服务的实例信息
     * @param config
     * @return
     */
    private static ServiceInstance buildGatewayServiceInstance(Config config) {
        String localIp = NetUtils.getLocalIp();
        int port = config.getPort();
        return ServiceInstance.builder()
                .serviceInstanceId(localIp + BasicConst.COLON_SEPARATOR + port)
                .ip(NetUtils.getLocalIp())
                .port(config.getPort())
                .registerTime(System.currentTimeMillis())
                .build();
    }

    private static void initAndGetConfig(Config config) {

        //java spi 机制
        ServiceLoader<ConfigCenter> serviceLoader = ServiceLoader.load(ConfigCenter.class);
        ConfigCenter configCenter = serviceLoader.iterator().next();
        if (configCenter == null){
            log.error("not found ConfigCenter impl");
            throw new RuntimeException("not found ConfigCenter impl");
        }
        //初始化
        configCenter.init(config.getRegistryAddress(), config.getEnv());
        //订阅监听
        configCenter.subscribeRuleChange(rules -> {
            DynamicConfigManager.getInstance().addRules(rules);
        });

    }
}
